﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

using System.Collections;
using System.Net;
using System.Net.Sockets;
using InfoFlash;
using System.Threading;
using System.Configuration;
namespace InfoFlashServer
{
    delegate void Function();
    public partial class Form1 : Form
    {

        private TcpListener ServerSocket {get;set;}
        private Thread ServerThread { get; set; }
        private bool ServerIsRunning { get; set; }
        private int ClientCounter { get; set; }
        private ClientManagers ClientManagers = new ClientManagers();
        private int Port { get { return Convert.ToInt32(ConfigurationManager.AppSettings["Port"].ToString().Trim()); } }
        public Form1()
        {
            InitializeComponent();
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            this.Text += " - " + LocalIPAddress();
            cbAction.SelectedIndex = 0;
            txtMessage.Text = "Server Started";
            ServerIsRunning = true;
            ServerThread = new Thread(StartListening);
            ServerThread.Start();
            tmrCheckConnected.Start();
            dateTimePicker1.Format = DateTimePickerFormat.Custom;
            dateTimePicker1.CustomFormat = "MM/dd/yyyy hh:mm:tt";
        }
        private void btnStart_Click(object sender, EventArgs e)
        {

        }
        private void StartListening()
        {

            try
            {
                IPAddress localAddr = IPAddress.Parse(LocalIPAddress());
                //TcpListener 
                ServerSocket = new TcpListener(localAddr, this.Port);
                TcpClient clientSocket = default(TcpClient);
                
                ServerSocket.Start();

                
                ClientCounter = 0;
                while (ServerIsRunning == true)
                {
                    ClientCounter += 1;
                    clientSocket = ServerSocket.AcceptTcpClient();


                    //DisplayMsg("Client No: " + Convert.ToString(counter) + " [" + clientSocket.Client.RemoteEndPoint.ToString() + "]  Started!");

                    ClientManager client = new ClientManager();
                    client.ClientMessageRecieved += new ClientMessageRecievedHandler(onClientMessageRecieved);
                    client.StartClient(clientSocket, Convert.ToString(ClientCounter));
                    ClientManagers.Add(client);
                    SendMessage(clientSocket, "WHOIS", "");
                }
            }
            catch (ThreadAbortException taex)
            {
                DisplayMsg(taex.Message);
            }
            catch (Exception ex)
            {
                DisplayMsg(ex.Message);
            }

        }
        private void DisplayMsg(string msg) {
            try
            {
                this.Invoke(new Function(delegate()
                {
                    txtMessage.AppendText("\r\n" + msg);
                }));
            }
            catch(Exception ex) {
                Console.WriteLine(ex.Message);
            }
        }
        private void onClientMessageRecieved(TcpClient tcpClient, MessageData data)
        {
            this.RemoveNotConnectedClients();
            switch (data.Code)
            {
                case "MSG":
                    DisplayMsg(GetPCName(tcpClient) + " [" + tcpClient.Client.RemoteEndPoint.ToString() + "] : " + data.Message);
                    this.SendMessage(tcpClient,"RECIEVED", data.Message); 
                    break;
                case "PCNAME":
                    SetPCName(tcpClient,data.Message);
                    //DisplayMsg("Client No: " + Convert.ToString(ClientCounter) + GetPCName(tcpClient) + " [" + tcpClient.Client.RemoteEndPoint.ToString() + "]  Started!");
                    DisplayMsg(GetPCName(tcpClient) + " [" + tcpClient.Client.RemoteEndPoint.ToString() + "]  Started!");

                        var pc = GetPCName(tcpClient) + " [" + tcpClient.Client.RemoteEndPoint.ToString() + "]";
                        bool isFound = false;
                        for (int x = 0; x < clbClients.Items.Count; x++)
                        {
                            if (clbClients.Items[x].ToString().Trim().ToUpper() == pc.Trim().ToUpper())
                            {
                                isFound = true;
                            }
                        }
                        if (isFound == false) {
                            this.Invoke(new Function(delegate(){
                                clbClients.Items.Add(pc);
                            }));
                        }

                    this.SendMessage(tcpClient, "RECIEVED", "Started!"); 
                    break;

                case "RECIEVED":
                    this.Invoke(new Function(delegate(){txtSend.Text = "";}));
                    DisplayMsg( data.Message);
                    break;
                case "ERROR":
                    DisplayMsg(GetPCName(tcpClient) + " [" + tcpClient.Client.RemoteEndPoint.ToString() + "] - Error :" + data.Message);
                    break;

                default: break;
            }

        }
        private string GetPCName(TcpClient tcpClient) {
            string result="";
            foreach (ClientManager cm in ClientManagers)
            {
                if (cm.ClientSocket.Connected)
                {
                    if (cm.ClientSocket.Client.RemoteEndPoint.ToString() == tcpClient.Client.RemoteEndPoint.ToString())
                    {
                        result = cm.ComputerName;
                        break;
                    }
                }
            }

            return result;
        }
        private void SetPCName(TcpClient tcpClient,string PCName)
        {
            foreach (ClientManager cm in ClientManagers)
            {
                if (cm.ClientSocket.Connected)
                {

                    if (cm.ClientSocket.Client.RemoteEndPoint.ToString() == tcpClient.Client.RemoteEndPoint.ToString())
                    {
                        cm.ComputerName = PCName;
                        cm.IPAddressAndPort = tcpClient.Client.RemoteEndPoint.ToString();
                        break;
                    }
                }
               

            }
        }
        private string LocalIPAddress()
        {
            IPHostEntry host;
            string localIP = "";
            host = Dns.GetHostEntry(Dns.GetHostName());
            foreach (IPAddress ip in host.AddressList)
            {
                if (ip.AddressFamily == AddressFamily.InterNetwork)
                {
                    localIP = ip.ToString();
                    break;
                }
            }
            return localIP;
        }
        private void btnSend_Click(object sender, EventArgs e)
        {
            string Message = "";
            string Action = "";
            switch (cbAction.Text.ToString().ToUpper())
            {
                case "MESSAGE": Message = "Server: " + txtSend.Text; Action = "MSG"; break;
                case "ALERT": Message = txtSend.Text; Action = "ALERT"; break;
                default: break;
            }


            foreach(ClientManager cm in ClientManagers){
                if (isFoundPCNameOnCheckItems(cm.ComputerName))
                {
                    SendMessage(cm.ClientSocket, Action, Message);
                }
            }

        }

        private bool isFoundPCNameOnCheckItems(string searchPCName) {
            bool isFound = false;
            for (int x = 0; x < clbClients.CheckedItems.Count; x++)
            {
                string pcname = clbClients.Items[x].ToString();
                pcname = pcname.Substring(0, pcname.IndexOf("["));
                pcname = pcname.Trim().ToLower();

                if (searchPCName.Trim().ToLower() == pcname) {
                    isFound = true;
                    break;
                }
            }

            return isFound;
        }

        private void SendMessage(TcpClient ClientSocket, string Code, string Message) {
            if (ClientSocket.Connected)
            {
                NetworkStream stream = ClientSocket.GetStream();
                MessageData md = new MessageData();
                md.Code = Code;
                md.Message = Message;
                Byte[] msg = MessageData.ToByteArray(md);
                stream.Write(msg, 0, msg.Length);
                stream.Flush();
            }
        }
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            ServerIsRunning =false;
            if (ServerSocket != null)
            {
                ServerSocket.Server.Close();
                ServerThread.Abort();
              //  Environment.Exit(0);
            }
            
        }
        private void RemoveNotConnectedClients()
        {
            try
            {
            CountClientsFlag:
                int CountClients = ClientManagers.Count;
                for (int i = 0; i < CountClients; i++)
                {
                    if (ClientManagers[i].ClientSocket.Connected == false)
                    {
                        RemovedClientInCheckListBox(ClientManagers[i]);
                        ClientManagers.RemoveAt(i);
                        goto CountClientsFlag;
                    }
                }
            }
            catch (Exception ex)
            {

                Console.WriteLine(ex.Message);
            }
        }
        private void tmrCheckConnected_Tick(object sender, EventArgs e)
        {
            RemoveNotConnectedClients();
        }

        public void RemovedClientInCheckListBox(ClientManager cm)
        {


            for (int x = 0; x < clbClients.Items.Count; x++)
            {
                string item = clbClients.Items[x].ToString();
                string _IPAddressAndPort = "";
                _IPAddressAndPort = item.Substring(item.IndexOf("[") + 1);
                _IPAddressAndPort = _IPAddressAndPort.Substring(0, _IPAddressAndPort.IndexOf("]"));
                if (cm.IPAddressAndPort == _IPAddressAndPort)
                {
                    clbClients.Items.RemoveAt(x);
                    this.DisplayMsg("Offline Client:" + cm.ComputerName + "[" + cm.IPAddressAndPort + "]");
                    break;
                }
            }
        }

    }




   





}
